#include "login_verify_task.h"
#include "../MessageProcess.h"
#include <core/sharedata/login_data.h>
#include <core/system/thread_wrapper.h>
#include <core/system/guard.h>
#include <core/QbLogger.h>
#include <core/strings/md5.h>
#include <qbprotocol/include/MessageParser.h>
#include <qbprotocol/include/rdMessage.h>
#include <qbprotocol/include/ssLoginProto.h>
#include <qbkernel/include/qb_base.h>
#include <uam/UserAccountManager.h>

#ifndef WIN32
#include <arpa/inet.h>
#endif

#define GateVersion	"V8"

namespace qb
{
    bool CLoginVerifyTask::m_bFirst = true;

    CLoginVerifyTask::CLoginVerifyTask()
    {
        memset(&m_data, 0, sizeof(xMessageInfo_t));
        memset(&m_HeadAck, 0, sizeof(m_HeadAck));
        memset(QB_Key, 0, 32);
        QB_Key[0x00000000] = 0x21;
        QB_Key[0x00000001] = 0x1d;
        QB_Key[0x00000002] = 0xae;
        QB_Key[0x00000003] = 0x7b;
        QB_Key[0x00000004] = 0xc4;
        QB_Key[0x00000005] = 0x20;
        QB_Key[0x00000006] = 0x66;
        QB_Key[0x00000007] = 0xae;
        QB_Key[0x00000008] = 0x98;
        QB_Key[0x00000009] = 0x43;
        QB_Key[0x0000000a] = 0x9e;
        QB_Key[0x0000000b] = 0xeb;
        QB_Key[0x0000000c] = 0x3b;
        QB_Key[0x0000000d] = 0x4e;
        QB_Key[0x0000000e] = 0x9e;
        QB_Key[0x0000000f] = 0xfe;

        if (m_bFirst)
        {
            m_bFirst = false;

            rdMessage::Init((char*)QB_Key);
        }
    }

    CLoginVerifyTask::~CLoginVerifyTask()
    {
        if (m_data.length > 0 && m_data.buffer) delete[] m_data.buffer;
    }

	void CLoginVerifyTask::StartImpl()
	{
		char buf[Y_RD_SERVICE_MESSAGE_BLOCK_LEN] = {0};
		int32_t buflen = 0;
		makeLoginData(buf, buflen);

		loginData::instance().SetCurrentStatus(eNetStatus_VerifyLogin);

		int nRet = qbBase::getMessageKernel()->Send(loginData::instance().ConnectID(), buf, buflen);
		if (nRet < 0)
		{
			log_error("OnConnectError");

			NotifyFailed(eNetStatus_VerifyLogin, eNetError_SendToServerFailed);
		}
	}

	void CLoginVerifyTask::makeLoginData(char* buf, int& buflen)
	{
		char* srtp = MD5String(loginData::instance().UserInfo().strRawPassword.c_str());
		if (srtp)
		{
			loginData::instance().UserInfo().strPassword = srtp;
		}

		xMsgHeadReq_t xhead;
		xLoginLgnSvrReq_t xBody;
		memset(&xBody, 0x00, sizeof(xBody));

		xhead.msgtype = htonl(E_FID_LGN_PRO_LOGIN_INFO_V2);
		strcpy(xBody.accountname, loginData::instance().UserInfo().strAccount.c_str());
		if(srtp != nullptr)
			strcpy(xBody.passwd, srtp);
		strcpy(xBody.loginType, "0");
		strcpy(xBody.buf, loginData::instance().UserInfo().strMac.c_str());
		strcpy(xBody.reserve, GateVersion);

		char tcTemp[Y_RD_PASSWD_LEN * 2];
		memset(tcTemp, 0, Y_RD_PASSWD_LEN * 2);
		int encryptlen = 0;
		char szKey[64];
		strcpy(szKey, Y_RD_AES_KEY_LOGIN);
		rdMessage::bEncryt(xBody.passwd, sizeof(xBody.passwd), tcTemp, &encryptlen, szKey);
		memcpy(xBody.passwd, tcTemp, Y_RD_PASSWD_LEN * 2);
		xBody.version = 20210101.0;

		rdMessage::bPack((char*)&xhead, sizeof(xhead), (char*)&xBody, sizeof(xBody), buf, &buflen);
	}

	void CLoginVerifyTask::TerminateImpl()
	{

	}

	void CLoginVerifyTask::OnNetData(char* pRecvData, int nDataLen)
	{
        QB_CHECK_RETURN_VOID1(pRecvData && nDataLen > 0);

		xMsgHeadAck_t xHead;
        memcpy(&xHead, pRecvData, sizeof(xHead));
		xHead.msgtype = ntohl(xHead.msgtype);
		xHead.retcode = ntohs(xHead.retcode);
		xHead.idx = ntohs(xHead.idx);
		xHead.num = ntohs(xHead.num);

		if (xHead.msgtype == E_FID_CS_FORCE_QUIT)
		{
			NotifyFailed(eNetStatus_VerifyLogin, eFT_PL_FORCE_QUIT);
			qbBase::getNetworkService()->NotifyForceQuit(loginData::instance().ConnectID());
		}
		else if (xHead.msgtype == E_FID_LGN_LOGIN_INFO || xHead.msgtype == E_FID_LGN_RE_NEW_LOGIN_INFO
			|| xHead.msgtype == E_FID_LGN_ENCRYPT_LOGIN_INFO || xHead.msgtype == E_FID_LGN_ENCRYPT_RE_LOGIN_INFO
			|| xHead.msgtype == E_FID_LGN_PRO_LOGIN_INFO_V2 || xHead.msgtype == E_FID_LGN_PRO_RE_LOGIN_INFO)
		{
			m_HeadAck = xHead;
			if (xHead.retcode == E_RC_OK || xHead.retcode == E_RC_IP_CHECK || xHead.retcode == E_RC_MAC_CHECK)
			{
				if (m_data.length > 0 && m_data.buffer) delete[] m_data.buffer;
				memset(&m_data, 0, sizeof(m_data));
                m_data.length = nDataLen - sizeof(xHead);
				if (m_data.length > 0)
				{
					m_data.buffer = new char[m_data.length];
                    memcpy(m_data.buffer, pRecvData + sizeof(xHead), m_data.length);
				}

				if (xHead.retcode == E_RC_IP_CHECK || xHead.retcode == E_RC_MAC_CHECK)
				{
					NotifyFailed(eNetStatus_VerifyLogin, xHead.retcode);

					return;
				}

				porcessLoginQPIDMessage(m_data, xHead);
				handle_ReqUserLogout();

				NotifyLoginStep(eNetStatus_VerifyLogin, 0);

				NotifyFinished();
			}
			else
			{
				NotifyFailed(eNetStatus_VerifyLogin, xHead.retcode);
			}
		}
	}

	int32_t CLoginVerifyTask::porcessLoginQPIDMessage(const xMessageInfo_t& data, const xMsgHeadAck_t& xHead)
	{
		if (data.length <= 0 || data.buffer == 0)
		{
			NotifyFailed(eNetStatus_VerifyLogin, eNetError_DataParseError);
			return -1;
		}

		MessageParser mPaser;
		SSAckMsg stAck;
		memset(&stAck, 0, sizeof(SSAckMsg));
		int iFunid = mPaser.GetMessageType(data.buffer, data.length, stAck);
		stAck.m_FuncID = iFunid;
		switch (iFunid)
		{
			case E_FID_LGN_PRO_LOGIN_INFO_V2:
			case E_FID_LGN_PRO_RE_LOGIN_INFO:
			{
				if (xHead.retcode == E_RC_OK || xHead.retcode == E_RC_IP_CHECK || xHead.retcode == E_RC_MAC_CHECK)
				{

					mPaser.SetDecodeFunc(auth::ExtracFunc);
					mPaser.DecodeMessage(&stAck);
					loginData::instance().SetLoginAck(*((xLoginLgnSvrProAck_t*)stAck.m_pRet));
					auth::ExtracFunc(iFunid, ProtoMessage(), stAck.m_pRet);

					if (m_data.length > 0 && m_data.buffer)
					{
						delete[] m_data.buffer;
						memset(&m_data, 0, sizeof(m_data));
					}
				}
				else
				{
					NotifyFailed(eNetStatus_VerifyLogin, xHead.retcode);
					return -1;
				}
				break;
			}
			default:
			{
				NotifyFailed(eNetStatus_VerifyLogin, eNetError_DataParseError);
				return -1;
			}
		}

		loginData::instance().UserInfo().strUserID = loginData::instance().GetLoginAck().userID;
		loginData::instance().UserInfo().strCookie = loginData::instance().GetLoginAck().cookie;
		loginData::instance().UserInfo().strCompanyId = loginData::instance().GetLoginAck().lastip;
		SSUserAccountManager::instance().SetUserInfo(loginData::instance().GetLoginAck().userID, loginData::instance().UserInfo().strPassword.c_str(), loginData::instance().GetLoginAck().lastip);

		if (loginData::instance().GetLoginAck().gwlist.size() == 0)
		{
			NotifyFailed(eNetStatus_VerifyLogin, eNetError_DataParseError);
			return -1;
		}

		std::list<xGWInfo_t>::iterator itor = loginData::instance().GetLoginAck().gwlist.begin();
		for (; itor != loginData::instance().GetLoginAck().gwlist.end(); itor++)
		{
			loginData::instance().SetGatewayLoginAddress(itor->ip, itor->port);

			break;
		}

		return 0;
	}

	void CLoginVerifyTask::handle_ReqUserLogout()
	{
		xMsgHeadReq_t xhead;
		xLogoutLgnSvReq_t xBody;
		memset(&xBody, 0, sizeof(xLogoutLgnSvReq_t));

		xhead.msgtype = htonl(E_FID_LGN_LOGOUT_INFO);
		strcpy(xBody.accountname, loginData::instance().UserInfo().strAccount.c_str());

		char sndBuf[Y_RD_SERVICE_MESSAGE_BLOCK_LEN] = { 0 };
		int off = 0;
		rdMessage::bPack((char*)&xhead, sizeof(xhead), (char*)&xBody, sizeof(xBody), sndBuf, &off);

		qbBase::getMessageKernel()->Send(loginData::instance().ConnectID(), sndBuf, off);
	}
}
